use async_graphql::*;
use rbatis::crud::CRUD;
use rbatis::plugin::page::PageRequest;
use maplit::hashmap;
use chrono::NaiveDateTime;
use rbatis::core::value::DateTimeNow;

use crate::entity::sys_user::{SysUser, InputSaveUser, InputUpdateUser};
use crate::utils::valid::Valid;

pub struct UserService;

impl UserService {
    pub async fn by_id(id: u32) -> rbatis::Result<SysUser> {
        let wrp = crate::DB.new_wrapper()
            .eq("is_delete", 0)
            .eq("id", id);
        crate::DB
            .fetch_by_wrapper::<SysUser>("", &wrp)
            .await
    }

    pub async fn exists(s: String) -> bool {
        Self::by_account(s).await.is_some()
    }

    pub async fn by_account(account: String) -> Option<SysUser> {
        let wrp = crate::DB.new_wrapper()
            .eq("is_delete", 0)
            .eq("account", account);
        match crate::DB.fetch_by_wrapper("", &wrp).await {
            Ok(r) => r,
            _ => None
        }
    }

    pub async fn list_page(p: u64) -> rbatis::Result<rbatis::plugin::page::Page<SysUser>> {
        let req = PageRequest::new(p, crate::CONFIG.page_size);
        let wrp = crate::DB.new_wrapper().eq("is_delete", 0);
        crate::DB.fetch_page_by_wrapper("", &wrp, &req).await
    }

    pub async fn delete(id: u32, token: String) -> bool {
        let usr = crate::utils::token::valid_token(&token).unwrap();
        let mut ob = SysUser::new();
        ob.id = Some(id);
        ob.is_delete = Some(1);
        ob.update_by = usr.id;
        ob.update_time = Some(NaiveDateTime::now());
        crate::DB.update_by_id("", &mut ob).await.is_ok()
    }

    pub async fn save(ob: InputSaveUser, token: String) -> Result<bool> {
        if ob.is_valid() {
            if Self::exists(ob.account.clone().unwrap()).await {
                return Err(Error::new("该用户已存在！"));
            }
            let usr = crate::utils::token::valid_token(&token).unwrap();
            let ins = SysUser {
                id: None,
                account: ob.account,
                name: ob.name,
                password: Some(crate::utils::password::password_hash(ob.password.unwrap().as_str())),
                version: Some(0),
                is_delete: Some(0),
                position: ob.position,
                create_by: usr.id,
                create_time: Some(NaiveDateTime::now()),
                update_by: usr.id,
                update_time: Some(NaiveDateTime::now())
            };

            crate::DB.save("", &ins).await?;

            Ok(true)
        } else {
            Err(Error::new("")
                .extend_with(|_, e| ob.with_content(e, "account", hashmap! {"required" => "请输入账号！", "length" => "账号请输入"}))
                .extend_with(|_, e| ob.with_content(e, "name", hashmap! {"required" => "请输入姓名！", "length" => "姓名请输入"}))
                .extend_with(|_, e| ob.with_content(e, "password", hashmap! {"required" => "请输入密码！", "length" => "密码请输入"}))
                .extend_with(|_, e| ob.with_content(e, "position", hashmap! {"required" => "请选择职位！", "range" => "请选择职位！"})))
        }
    }

    pub async fn update(ob: InputUpdateUser, token: String) -> Result<bool> {
        if ob.is_valid() {
            if let Ok(mut upd) = Self::by_id(ob.id.unwrap()).await {
                if upd.version.unwrap() != ob.version {
                    return Err(Error::new("该用户已被其它账号修改！"));
                }

                let usr = crate::utils::token::valid_token(&token).unwrap();

                upd.account = ob.account;
                upd.name = ob.name;
                upd.position = ob.position;
                upd.version = Some(ob.version + 1);
                upd.update_by = usr.id;
                upd.update_time = Some(NaiveDateTime::now());

                crate::DB.update_by_id::<SysUser>("", &mut upd).await?;
            } else {
                return Err(Error::new("该用户不存在！"));
            }

            Ok(true)
        } else {
            Err(Error::new("")
                .extend_with(|_, e| ob.with_content(e, "account", hashmap! {"required" => "请输入账号！", "length" => "账号请输入"}))
                .extend_with(|_, e| ob.with_content(e, "name", hashmap! {"required" => "请输入姓名！", "length" => "姓名请输入"}))
                .extend_with(|_, e| ob.with_content(e, "position", hashmap! {"required" => "请选择职位！", "range" => "请选择职位！"})))
        }
    }
}